package yartiss.framework.view;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.swing.JSplitPane;
import javax.swing.JTextField;

@SuppressWarnings("serial")
public abstract class AbstractView extends JSplitPane implements IView {

	protected final Map<String, Field> properties;
	protected static List<String> propertiesNames = new ArrayList<String>();

	protected AbstractView(){
		properties 	  = getProperties(this.getClass());
	}

	private static Map<String, Field> getProperties(Class<? extends AbstractView> clazz) {
		Map<String, Field> props = new HashMap<String, Field>();
		for (Field field : clazz.getDeclaredFields()) {
			if(field.getName().endsWith("Field")){
				String propName = field.getName().substring(0,field.getName().length()-"Field".length()).toLowerCase();
				props.put(propName, field);
				propertiesNames.add(propName);
			}
		}
		return props;
	}

	@SuppressWarnings("unchecked")
	public <T> T getProperty(String propertyName){
		propertyName = propertyName.toLowerCase();
		try {
			Field field = (properties.containsKey(propertyName) ? properties.get(propertyName) : null);
			if(field != null){
				Method  method = null;
				Object value = null;
				try{
					JTextField obj = (JTextField) field.get(this);
					method = obj.getClass().getMethod("getText");
					value = method.invoke(obj);
				}
				catch (Exception e) {
					e.printStackTrace();
				}
				return (T)value;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public <T> void setProperty(String propertyName, T value){
		propertyName = propertyName.toLowerCase();
		try {
			Field field = (properties.containsKey(propertyName) ? properties.get(propertyName) : null);
			if(field != null){
				Object obj = field.get(this);
				Method  method = obj.getClass().getMethod("setText", String.class);
				String val = value != null ? value.toString() : "";
				method.invoke(obj, val);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private Map<String,List<PropertyChangeListener>> listenersByProperty = new HashMap<String, List<PropertyChangeListener>>();
	private List<PropertyChangeListener> listeners = new LinkedList<PropertyChangeListener>();

	public void registerPropertyChangeListerner(PropertyChangeListener listener) {
		listeners.add(listener);
	}

	@Override
	public void registerPropertyChangeListerner(String propertyName, PropertyChangeListener listener) {
		List<PropertyChangeListener> ls = (listenersByProperty.containsKey(propertyName) ? listenersByProperty.get(propertyName) : null);
		if(ls == null) ls = new LinkedList<PropertyChangeListener>();
		ls.add(listener);
		listenersByProperty.put(propertyName, ls);
	}

	@Override
	public void unregisterPropertyChangeListener(PropertyChangeListener listener) {
		if(listeners.contains(listener))
			listeners.remove(listener);
		if(listenersByProperty.containsValue(listener)){
			//TODO
		}
	}

	protected void fireGuiPropertyChanged(String propertyName, Object oldValue, Object newValue ){
		for (PropertyChangeListener l : listeners) {
			l.propertyChange(new PropertyChangeEvent(this, propertyName, oldValue, newValue));
		}
		if(listenersByProperty.containsKey(propertyName)){
			for (PropertyChangeListener l : listenersByProperty.get(propertyName)) {
				l.propertyChange(new PropertyChangeEvent(this, propertyName, oldValue, newValue));
			}
		}
	}
}
